﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;

public class TcpClientCore : ClientBase
{

    private bool isConnect = false;
    private bool isConnecting = false;
    private bool isConnectTimeOut = false;
    
    public TcpClientCore()
    {
        isServer = false;
    }
    /// <summary>
    /// 启动连接
    /// </summary>
    /// <param name="ip"></param>
    /// <param name="port"></param>
    /// <param name="timeout"></param>
    public void Connect(string ip, string port, int timeOut, bool isPacketDecode)
    {
        if (isConnecting || isConnect)
            return;
        isConnecting = true;
        CoreEvent cevent = new CoreEvent();
        cevent.eventType = NetEventType.SC_BEGIN_CONNECT;
        NetCore.AddEvent(cevent);
        
        EndPoint iep = null;
        CoreEvent ce = new CoreEvent();
        if (!NetCore.VerifyEndPoint(ip, port, ref iep, ref ce))
        {
            NetCore.AddEvent(ce);
            isConnecting = false;
            return;
        }

        this.isPacketDecode = isPacketDecode;
        //this.ceEvent = ceEvent;

        new Thread(() =>
        {
            mux.WaitOne();
            if (clientSocket == null)
            {
                clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            }

            IAsyncResult result = clientSocket.BeginConnect(iep, ConnectSuccessCB, null);
            mux.ReleaseMutex();
            //如果等待之前先退出上下文的同步域（如果在同步上下文中），并在稍后重新获取它，则为 true；否则为 false。
            //如果当前实例收到信号，则为 true；否则为 false。
            result.AsyncWaitHandle.WaitOne(timeOut, false);
            //result.AsyncWaitHandle.WaitOne()
            isConnectTimeOut = false;
            if (!result.IsCompleted)
            {
                isConnectTimeOut = true;
                Clear();
                //ip=xxx.xxx.xxx.xxxx
                CoreEvent timeOutce = new CoreEvent();
                timeOutce.eventType = NetEventType.SC_CONNECT_TIMEOUT;
                NetCore.AddEvent(timeOutce);
            }
            isConnecting = false;

        }).Start();

    }

    private void ConnectSuccessCB(IAsyncResult ar)
    {

        mux.WaitOne();
        try
        {
            clientSocket.EndConnect(ar);
        }
        catch (Exception ex)
        {
            if(!isConnectTimeOut)
            {
                CoreEvent ce = new CoreEvent();
                ce.eventType = NetEventType.SC_CONNECT_EXCEPTION;
                ce.log = ex.Message;
                NetCore.AddEvent(ce);
            }
            mux.ReleaseMutex();
            return;
        }
        mux.ReleaseMutex();

        //连接成功
        CoreEvent sce = new CoreEvent();
        sce.eventType = NetEventType.SC_CONNECT_SUCCESS;
        NetCore.AddEvent(sce);
        isConnect = true;
        //启动接收

        mux.WaitOne();
        try
        {
            clientSocket.BeginReceive(readBuff, 0, MAX_BUFF_LENGTH, SocketFlags.None, ReceiveCb, null);
            mux.ReleaseMutex();
        }
        catch (Exception ex)
        {
            mux.ReleaseMutex();
            CoreEvent ce = new CoreEvent();
            ce.eventType = NetEventType.COMM_START_ASYNC_RECEIVE_THREAD_FAILED;
            ce.log = ex.Message;
            NetCore.AddEvent(ce);
        }


    }

    public void Disconnect()
    {
        Close(NetEventType.COMM_DISCONNECT_INITIATIVE, "主动断开");
    }

    /// <summary>
    /// 断开连接 并清理
    /// </summary>
    protected override void Close(NetEventType type, string log)
    {
        CoreEvent ce = new CoreEvent();
        ce.eventType = type;
        ce.log = log;
        ce.data = null;
        NetCore.AddEvent(ce);

        isConnect = false;
        mux.WaitOne();
        if (clientSocket == null)
        {
            mux.ReleaseMutex();
            return;
        }
       
        if (clientSocket.Connected)
        {
            clientSocket.Shutdown(SocketShutdown.Both);
        }

        Clear();
        mux.ReleaseMutex();

    }
    private void Clear()
    {
        clientSocket.Close();
        clientSocket = null;
    }


    public override int Send(byte[] msg)
    {
        if (clientSocket == null) return 0;
        try
        {
            return clientSocket.Send(msg);
        }
        catch (Exception ex)
        {
            //Close();
            NetCore.LogWarning(ex);
            return 0;
        }
    }
}
